package com.lg.zookeeper.watch;

import com.lg.zookeeper.entity.Config;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;

/**
 * 创建一个类，实现Watcher，CallBack接口，既可以监听服务端配置，又可以封装CallBack方法，对服务端状态做处理
 *
 * @author by Mr. Li 2020/12/10 14:12
 */
public class DefaultWatchCallBack implements Watcher, AsyncCallback.StatCallback, AsyncCallback.DataCallback {

    private ZooKeeper zooKeeper;    //添加一个对象引用，采用异步编程模型，主线程启动后，将主线程获取到的zookeeper对象传递过来，保证操作的是与服务端通信成功的同一个对象
    private Config conf;            //创建一个配置实体类，可以满足两个线程对一个对象的操作，实现线程间数据传递
    private CountDownLatch latch = new CountDownLatch(1);   //锁，阻塞

    /**
     * 获取服务端数据，返回至客户端
     *
     * @param i
     * @param s
     * @param o
     * @param bytes
     * @param stat
     */
    public void processResult(int i, String s, Object o, byte[] bytes, Stat stat) {
        if (bytes != null) {
            conf.setConf(new String(bytes));
            latch.countDown();   //数据存在，数据设置到实体类，释放锁，zookeeper调用的主线程获取数据
        }
    }

    /**
     * 获取服务端数据，返回至客户端
     *
     * @param i
     * @param s
     * @param o
     * @param stat
     */
    public void processResult(int i, String s, Object o, Stat stat) {
        if (stat != null) {
            zooKeeper.getData("/AppConf", this, this, "A");
        }
    }

    /**
     * watch接口
     * 这里可以实时监控节点的变化信息。实时的跟新最新的配置信息
     *
     * @param watchedEvent
     */
    public void process(WatchedEvent watchedEvent) {
        switch (watchedEvent.getType()) {
            case None:
            case DataWatchRemoved:
            case NodeChildrenChanged:
            case ChildWatchRemoved:
                break;
            case NodeCreated:
                zooKeeper.getData("/AppConf", this, this, "B");    //节点创建时，获取服务端数据并返回
                break;
            case NodeDeleted:
                conf.setConf("");
                latch = new CountDownLatch(1);  //当节点数据被删除后，重置实体类数据，阻塞等待
                break;
            case NodeDataChanged:
                zooKeeper.getData("/AppConf", this, this, "C");    //节点数据改变时，再次获取服务器端数据
                break;
        }
    }

    /**
     * 判断节点数据是否存在，获取结果成功后返回，否则阻塞等待
     */
    public void aWait() {
        try {
            zooKeeper.exists("/AppConf", this, this, "D");
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public ZooKeeper getZooKeeper() {
        return zooKeeper;
    }

    public void setZooKeeper(ZooKeeper zooKeeper) {
        this.zooKeeper = zooKeeper;
    }

    public Config getConf() {
        return conf;
    }

    public void setConf(Config conf) {
        this.conf = conf;
    }

    public CountDownLatch getLatch() {
        return latch;
    }

    public void setLatch(CountDownLatch latch) {
        this.latch = latch;
    }
}
